package com.leetcode.traceback;

import java.util.LinkedList;

public class SearchWord {
    public static void main(String[] args) {
        char[][] board = {{'A','B','C','E'},{'S','F','E','S'},{'A','D','E','E'}};
        String word = "ABCESEEEFS";
        SearchWord searchWord = new SearchWord();
        searchWord.exist(board, word);
    }

    public boolean exist(char[][] board, String word) {
        int row = board.length;
        int col = board[0].length;
        boolean[][] isVisited = new boolean[row][col];
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (backTrace(board, isVisited, i, j, word, 0)) {
                    return true;
                }
            }
        }
        return false;
    }

    private final int[][] MOVE = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

    public boolean backTrace(char[][] board, boolean[][] isVisited, int i, int j,
                       String word, int ind) {
        if (word.charAt(ind) != board[i][j]) {
            return false;
        } else if (word.length() - 1 == ind) {
            return true;
        }
        boolean res = false;
        isVisited[i][j] = true;
        for (int[] move : MOVE) {
            int newI = move[0] + i;
            int newJ = move[1] + j;
            if (newI >= 0 && newI < board.length && newJ >= 0 && newJ < board[0].length
                && !isVisited[newI][newJ]) {
                boolean flag = backTrace(board, isVisited, newI, newJ, word, ind+1);
                if (flag) {
                    res = true;
                    break;
                }
            }
        }
        isVisited[i][j] = false;
        return res;
    }

    public boolean bfs(char[][] board, String word, int curR, int curC) {
        int row = board.length;
        int col = board[0].length;
        boolean[][] visited = new boolean[row][col];
        LinkedList<int[]> queue = new LinkedList<>();
        queue.offer(new int[]{curR, curC});
        int ind = 1;
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                if (ind == word.length()) {
                    return true;
                }
                int[] cur = queue.poll();
                for (int[] move : MOVE) {
                    int nextR = cur[0] + move[0];
                    int nextC = cur[1] + move[1];
                    if (nextR >= 0 && nextR < row && nextC >= 0 && nextC < col
                            && !visited[nextR][nextC]
                            && word.charAt(ind) == board[nextR][nextC]) {
                        queue.offer(new int[]{nextR, nextC});
                        visited[nextR][nextC] = true;
                    }
                }
            }
            ind++;
        }
        return false;
    }
}
